

/**
 * @file DataStructures.cpp
 * Set of several data structures to be used by other GPSTk classes.
 */

//============================================================================
//
//  Revision
//
//  2012/06/19   Add 'getGnssRinex(SatID& sat)' method for class sourceRinex.
//               The new method will return the first gnssRinex data which
//               contain the given satellite. ( 2012/06/19 )
//
//  2014/03/16   add the sourceNumber for 'source' in header.
//               f.header.source.sourceNumber= roh.markerNumber;
//
//  2014/07/15   Define a temporary 'source' to initialize the value of
//               the source in header; (shjzhang)
//
//============================================================================


#include "DataStructures.hpp"

using namespace gpstk::StringUtils;
using namespace std;

namespace gpstk
{


      ////// typeValueMap //////


      // Return a TypeIDSet with all the data types present in
      // this object.
    TypeIDSet typeValueMap::getTypeID() const
    {

        TypeIDSet typeSet;

        for( typeValueMap::const_iterator pos = (*this).begin();
             pos != (*this).end();
             ++pos )
        {
            typeSet.insert( (*pos).first );
        }

        return typeSet;

    }  // End of method 'typeValueMap::getTypeID()'



      // Return a typeValueMap with only this type of data.
      // @param type Type of value to be extracted.
    typeValueMap typeValueMap::extractTypeID(const TypeID& type) const
    {

        TypeIDSet typeSet;
        typeSet.insert(type);

        return extractTypeID(typeSet);

    }  // End of method 'typeValueMap::extractTypeID()'



      // Return a typeValueMap with only these types of data.
      // @param typeSet Set (TypeIDSet) containing the types of data to
      //                be extracted.
    typeValueMap typeValueMap::extractTypeID(const TypeIDSet& typeSet) const
    {

        typeValueMap tvMap;

        for( TypeIDSet::const_iterator pos = typeSet.begin();
             pos != typeSet.end();
             ++pos )
        {

            typeValueMap::const_iterator itObs( (*this).find(*pos) );
            if( itObs != (*this).end() )
            {
                tvMap[ (*itObs).first ] = (*itObs).second;
            }
        }

        return tvMap;

    }  // End of method 'typeValueMap::extractTypeID()'



      // Modifies this object, keeping only this type of data.
      // @param type Type of value to be kept.
    typeValueMap& typeValueMap::keepOnlyTypeID(const TypeID& type)
    {

        TypeIDSet typeSet;
        typeSet.insert(type);

        return (keepOnlyTypeID(typeSet));

    }  // End of method 'typeValueMap::keepOnlyTypeID()'



      // Modifies this object, keeping only these types of data.
      // @param typeSet Set (TypeIDSet) containing the types of data
      //                to be kept.
    typeValueMap& typeValueMap::keepOnlyTypeID(const TypeIDSet& typeSet)
    {

        typeValueMap tvMap( (*this).extractTypeID(typeSet) );
        (*this) = tvMap;

        return (*this);

    }  // End of method 'typeValueMap::keepOnlyTypeID()'



      // Modifies this object, removing these types of data.
      // @param typeSet Set (TypeIDSet) containing the types of data
      //                to be kept.
    typeValueMap& typeValueMap::removeTypeID(const TypeIDSet& typeSet)
    {

        for( TypeIDSet::const_iterator pos = typeSet.begin();
             pos != typeSet.end();
             ++pos )
        {
            (*this).erase(*pos);
        }

        return (*this);

    }  // End of method 'typeValueMap::removeTypeID()'



      /* Return the data value (double) corresponding to provided type.
       *
       * @param type       Type of value to be looked for.
       */
    double typeValueMap::getValue(const TypeID& type) const
        noexcept(false)
    {

        typeValueMap::const_iterator itObs( (*this).find(type) );
        if ( itObs != (*this).end() )
        {
            return (*itObs).second;
        }
        else
        {
            string typeStr = asString(type);
            GPSTK_THROW(TypeIDNotFound(typeStr+"TypeID not found in map"));
        }

    }  // End of method 'typeValueMap::getValue()'



      // Return a reference to the data value (double) with
      // corresponding type.
      // @param type Type of value to be looked for.
    double& typeValueMap::operator()(const TypeID& type)
        noexcept(false)
    {

        typeValueMap::iterator itObs ( (*this).find(type) );

        if ( itObs != (*this).end() )
        {
            return (*itObs).second;
        }
        else
        {
            GPSTK_THROW(TypeIDNotFound("TypeID not found in map"));
        }

    }  // End of method 'typeValueMap::operator()'


      // Convenience output method for structure satTypeValueMap
    std::ostream& typeValueMap::dump( std::ostream& s, int mode ) const
    {

        for(typeValueMap::const_iterator itObs = (*this).begin();
            itObs != (*this).end();
            ++itObs)
        {

            if (mode==1)
            {
                s << (*itObs).first << " ";
            }

            s << setprecision(12) ;
            s << (*itObs).second << " ";

        }  // End of 'for( typeValueMap::const_iterator itObs = ...'

         // Let's return the 'std::ostream'
        return s;

    }  // End of method 'satTypeValueMap::dump()'



      ////// satValueMap //////


      // Return a SatIDSet with all the satellites present in this object.
    SatIDSet satValueMap::getSatID() const
    {

        SatIDSet satSet;

        for( satValueMap::const_iterator pos = (*this).begin();
             pos != (*this).end();
             ++pos )
        {
            satSet.insert( (*pos).first );
        }

        return satSet;

    }  // End of method 'satValueMap::getSatID()'



      // Return a Vector with all the satellites present in this object.
    Vector<SatID> satValueMap::getVectorOfSatID() const
    {

        std::vector<SatID> temp;

        for( satValueMap::const_iterator pos = (*this).begin();
             pos != (*this).end();
             ++pos )
        {
            temp.push_back( (*pos).first );
        }

        Vector<SatID> result;
        result = temp;

        return result;

    }  // End of method 'satValueMap::getVectorOfSatID()'



      // Return a satValueMap with only this satellite.
      // @param satellite Satellite to be extracted.
    satValueMap satValueMap::extractSatID(const SatID& satellite) const
    {

        SatIDSet satSet;
        satSet.insert(satellite);

        return extractSatID(satSet);

    }  // End of method 'satValueMap::extractSatID()'



      // Return a satValueMap with only one satellite, identified by
      // the given parameters.
      // @param p Satellite PRN number.
      // @param p System the satellite belongs to.
    satValueMap satValueMap::extractSatID( const int& p,
                                           const SatelliteSystem::Systems& s ) const
    {

        SatID tempSatellite(p, s);  // We build a temporary SatID object

        return extractSatID(tempSatellite);

    }  // End of method 'satValueMap::extractSatID()'



      // Return a satValueMap with only these satellites.
      // @param satSet Set (SatIDSet) containing the satellites to
      //               be extracted.
    satValueMap satValueMap::extractSatID(const SatIDSet& satSet) const
    {

        satValueMap svMap;

        for( SatIDSet::const_iterator pos = satSet.begin();
             pos != satSet.end();
             ++pos )
        {
            satValueMap::const_iterator itObs( (*this).find(*pos) );

            if( itObs != (*this).end() )
            {
                svMap[ (*itObs).first ] = (*itObs).second;
            }
        }

        return svMap;

    }  // End of method 'satValueMap::extractSatID()'



      // Modifies this object, keeping only this satellite.
      // @param satellite Satellite to be kept.
    satValueMap& satValueMap::keepOnlySatID(const SatID& satellite)
    {

        SatIDSet satSet;
        satSet.insert(satellite);

        return keepOnlySatID(satSet);

    }  // End of method 'satValueMap::keepOnlySatID()'



      // Modifies this object, keeping only this satellite.
      // @param p Satellite PRN number.
      // @param p System the satellite belongs to.
    satValueMap& satValueMap::keepOnlySatID( const int& p,
                                             const SatelliteSystem::Systems& s )
    {

        SatID tempSatellite(p, s);  // We build a temporary SatID object

        return keepOnlySatID(tempSatellite);

    }  // End of method 'satValueMap::keepOnlySatID()'



      // Modifies this object, keeping only these satellites.
      // @param satSet Set (SatIDSet) containing the satellites to be kept.
    satValueMap& satValueMap::keepOnlySatID(const SatIDSet& satSet)
    {

        satValueMap svMap = extractSatID(satSet);
        (*this) = svMap;

        return (*this);

    }  // End of method 'satValueMap::keepOnlySatID()'



      // Modifies this object, removing these satellites.
      // @param satSet Set (SatIDSet) containing the satellites to
      //               be removed.
    satValueMap& satValueMap::removeSatID(const SatIDSet& satSet)
    {

        for( SatIDSet::const_iterator pos = satSet.begin();
             pos != satSet.end();
             ++pos )
        {
            (*this).erase(*pos);
        }

        return (*this);

    }  // End of method 'satValueMap::removeSatID()'



      /* Return the data value (double) corresponding to provided SatID.
       *
       * @param satellite     Satellite to be looked for.
       */
    double satValueMap::getValue(const SatID& satellite) const
        noexcept(false)
    {

        satValueMap::const_iterator itObs( (*this).find(satellite) );
        if ( itObs != (*this).end() )
        {
            return (*itObs).second;
        }
        else
        {
            GPSTK_THROW(SatIDNotFound("SatID not found in map"));
        }

    }  // End of method 'satValueMap::getValue()'



      // Return a reference to the data value (double) with
      // corresponding SatID.
      // @param satellite Satellite to be looked for.
    double& satValueMap::operator()(const SatID& satellite)
        noexcept(false)
    {

        satValueMap::iterator itObs( (*this).find(satellite) );

        if ( itObs != (*this).end() )
        {
            return (*itObs).second;
        }
        else
        {
            GPSTK_THROW(SatIDNotFound("SatID not found in map"));
        }

    }  // End of method 'satValueMap::operator()'


      // Convenience output method for structure satValueMap
    std::ostream& satValueMap::dump( std::ostream& s, int mode ) const
    {

        for(satValueMap::const_iterator it = (*this).begin();
            it != (*this).end();
            ++it)
        {

            // First, print satellite (system and PRN)
            s << (*it).first << " " << (*it).second;
            s << endl;

        }  // End of 'for( satValueMap::const_iterator it = ...'

         // Let's return the 'std::ostream'
        return s;

    }  // End of method 'satValueMap::dump()'



      ////// sourceValueMap //////


      // Return a SourceIDSet with all the sources present in this object.
    SourceIDSet sourceValueMap::getSourceID() const
    {

        SourceIDSet sourceSet;

        for( sourceValueMap::const_iterator pos = (*this).begin();
             pos != (*this).end();
             ++pos )
        {
            sourceSet.insert( (*pos).first );
        }

        return sourceSet;

    }  // End of method 'sourceValueMap::getSourceID()'



      // Return a Vector with all the sources present in this object.
    Vector<SourceID> sourceValueMap::getVectorOfSourceID() const
    {

        std::vector<SourceID> temp;

        for( sourceValueMap::const_iterator pos = (*this).begin();
             pos != (*this).end();
             ++pos )
        {
            temp.push_back( (*pos).first );
        }

        Vector<SourceID> result;
        result = temp;

        return result;

    }  // End of method 'sourceValueMap::getVectorOfSourceID()'



      // Return a sourceValueMap with only this source.
      // @param source Source to be extracted.
    sourceValueMap sourceValueMap::extractSourceID(const SourceID& source) const
    {

        SourceIDSet sourceSet;
        sourceSet.insert(source);

        return extractSourceID(sourceSet);

    }  // End of method 'sourceValueMap::extractSourceID()'



      // Return a sourceValueMap with only these sources.
      // @param sourceSet Set (SourceIDSet) containing the sources to
      //               be extracted.
    sourceValueMap sourceValueMap::extractSourceID(const SourceIDSet& sourceSet) const
    {

        sourceValueMap svMap;

        for( SourceIDSet::const_iterator pos = sourceSet.begin();
             pos != sourceSet.end();
             ++pos )
        {
            sourceValueMap::const_iterator itObs( (*this).find(*pos) );

            if( itObs != (*this).end() )
            {
                svMap[ (*itObs).first ] = (*itObs).second;
            }
        }

        return svMap;

    }  // End of method 'sourceValueMap::extractSourceID()'



      // Modifies this object, keeping only this source.
      // @param source Source to be kept.
    sourceValueMap& sourceValueMap::keepOnlySourceID(const SourceID& source)
    {

        SourceIDSet sourceSet;
        sourceSet.insert(source);

        return keepOnlySourceID(sourceSet);

    }  // End of method 'sourceValueMap::keepOnlySourceID()'



      // Modifies this object, keeping only these sources.
      // @param sourceSet Set (SourceIDSet) containing the sources to be kept.
    sourceValueMap& sourceValueMap::keepOnlySourceID(const SourceIDSet& sourceSet)
    {

        sourceValueMap svMap = extractSourceID(sourceSet);
        (*this) = svMap;

        return (*this);

    }  // End of method 'sourceValueMap::keepOnlySourceID()'



      // Modifies this object, removing these sources.
      // @param sourceSet Set (SourceIDSet) containing the sources to
      //               be removed.
    sourceValueMap& sourceValueMap::removeSourceID(const SourceIDSet& sourceSet)
    {

        for( SourceIDSet::const_iterator pos = sourceSet.begin();
             pos != sourceSet.end();
             ++pos )
        {
            (*this).erase(*pos);
        }

        return (*this);

    }  // End of method 'sourceValueMap::removeSourceID()'



      /* Return the data value (double) corresponding to provided SourceID.
       *
       * @param source     Source to be looked for.
       */
    double sourceValueMap::getValue(const SourceID& source) const
        noexcept(false)
    {

        sourceValueMap::const_iterator itObs( (*this).find(source) );
        if ( itObs != (*this).end() )
        {
            return (*itObs).second;
        }
        else
        {
            GPSTK_THROW(SourceIDNotFound("SourceID not found in map"));
        }

    }  // End of method 'sourceValueMap::getValue()'



      // Return a reference to the data value (double) with
      // corresponding SourceID.
      // @param source Source to be looked for.
    double& sourceValueMap::operator()(const SourceID& source)
        noexcept(false)
    {

        sourceValueMap::iterator itObs( (*this).find(source) );

        if ( itObs != (*this).end() )
        {
            return (*itObs).second;
        }
        else
        {
            GPSTK_THROW(SourceIDNotFound("SourceID not found in map"));
        }

    }  // End of method 'sourceValueMap::operator()'



      ////// satTypeValueMap //////


      /* Return the total number of data elements in the map.
       * This method DOES NOT suppose that all the satellites have
       * the same number of type values.
       */
    size_t satTypeValueMap::numElements() const
    {

        size_t numEle(0);

        for( satTypeValueMap::const_iterator it = (*this).begin();
             it != (*this).end();
             ++it )
        {
            numEle = numEle + (*it).second.size();
        }

        return numEle;

    }  // End of method 'satTypeValueMap::numElements()'



      // Return a SatIDSet with all the satellites present in this object.
    SatIDSet satTypeValueMap::getSatID() const
    {

        SatIDSet satSet;

        for( satTypeValueMap::const_iterator pos = (*this).begin();
             pos != (*this).end();
             ++pos )
        {
            satSet.insert( (*pos).first );
        }

        return satSet;

    }  // End of method 'satTypeValueMap::getSatID()'



      // Return a Vector with all the satellites present in this object.
    Vector<SatID> satTypeValueMap::getVectorOfSatID() const
    {

        std::vector<SatID> temp;

        for( satTypeValueMap::const_iterator pos = (*this).begin();
             pos != (*this).end();
             ++pos )
        {
            temp.push_back( (*pos).first );
        }

        Vector<SatID> result;
        result = temp;

        return result;

    }  // End of method 'satTypeValueMap::getVectorOfSatID()'



      // Return a TypeIDSet with all the data types present in
      // this object. This does not imply that all satellites have these types.
    TypeIDSet satTypeValueMap::getTypeID() const
    {

        TypeIDSet typeSet;

        for( satTypeValueMap::const_iterator pos = (*this).begin();
             pos != (*this).end();
             ++pos )
        {

            for( typeValueMap::const_iterator it = (*pos).second.begin();
                 it != (*pos).second.end();
                 ++it )
            {
                typeSet.insert( (*it).first );
            }

        }

        return typeSet;

    }  // End of method 'satTypeValueMap::getTypeID()'



      // Return a satTypeValueMap with only this satellite.
      // @param satellite Satellite to be extracted.
    satTypeValueMap satTypeValueMap::extractSatID(const SatID& satellite) const
    {

        SatIDSet satSet;
        satSet.insert(satellite);

        return extractSatID(satSet);

    }  // End of method 'satTypeValueMap::extractSatID()'



      // Return a satTypeValueMap with only one satellite, identified
      // by the given parameters.
      // @param p Satellite PRN number.
      // @param p System the satellite belongs to.
    satTypeValueMap satTypeValueMap::extractSatID( const int& p,
                                                   const SatelliteSystem::Systems& s ) const
    {

        SatID tempSatellite(p, s);  // We build a temporary SatID object

        return extractSatID(tempSatellite);

    }  // End of method 'satTypeValueMap::extractSatID()'



      // Return a satTypeValueMap with only these satellites.
      // @param satSet Set (SatIDSet) containing the satellites to
      //               be extracted.
    satTypeValueMap satTypeValueMap::extractSatID(const SatIDSet& satSet) const
    {

        satTypeValueMap stvMap;

        for( SatIDSet::const_iterator pos = satSet.begin();
             pos != satSet.end();
             ++pos )
        {
            satTypeValueMap::const_iterator itObs( (*this).find(*pos) );
            if( itObs != (*this).end() )
            {
                stvMap[ (*itObs).first ] = (*itObs).second;
            }
        }

        return stvMap;

    }  // End of method 'satTypeValueMap::extractSatID()'



      // Modifies this object, keeping only this satellite.
      // @param satellite Satellite to be kept.
    satTypeValueMap& satTypeValueMap::keepOnlySatID(const SatID& satellite)
    {

        SatIDSet satSet;
        satSet.insert(satellite);

        return keepOnlySatID(satSet);

    }  // End of method 'satTypeValueMap::keepOnlySatID()'



      // Modifies this object, keeping only this satellite.
      // @param p Satellite PRN number.
      // @param p System the satellite belongs to.
    satTypeValueMap& satTypeValueMap::keepOnlySatID( const int& p,
                                                     const SatelliteSystem::Systems& s )
    {

        SatID tempSatellite(p, s);  // We build a temporary SatID object

        return keepOnlySatID(tempSatellite);

    }  // End of method 'satTypeValueMap::keepOnlySatID()'



      // Modifies this object, keeping only these satellites.
      // @param satSet Set (SatIDSet) containing the satellites to be kept.
    satTypeValueMap& satTypeValueMap::keepOnlySatID(const SatIDSet& satSet)
    {

        satTypeValueMap stvMap( extractSatID(satSet) );
        (*this) = stvMap;

        return (*this);

    }  // End of method 'satTypeValueMap::keepOnlySatID()'



      // Return a satTypeValueMap with only this type of value.
      // @param type Type of value to be extracted.
    satTypeValueMap satTypeValueMap::extractTypeID(const TypeID& type) const
    {

        TypeIDSet typeSet;
        typeSet.insert(type);

        return extractTypeID(typeSet);

    }  // End of method 'satTypeValueMap::extractTypeID()'



      // Return a satTypeValueMap with only these types of data.
      // @param typeSet Set (TypeIDSet) containing the types of data
      //                to be extracted.
    satTypeValueMap satTypeValueMap::extractTypeID(const TypeIDSet& typeSet) const
    {

        satTypeValueMap theMap;

        for( satTypeValueMap::const_iterator it = (*this).begin();
             it != (*this).end();
             ++it )
        {

            typeValueMap tvMap( (*it).second.extractTypeID(typeSet) );
            if( tvMap.size() > 0 )
            {
                theMap[(*it).first] = tvMap;
            }

        }

        return theMap;

    }  // End of method 'satTypeValueMap::extractTypeID()'



      // Modifies this object, keeping only this type of data.
      // @param type Type of value to be kept.
    satTypeValueMap& satTypeValueMap::keepOnlyTypeID(const TypeID& type)
    {

        TypeIDSet typeSet;
        typeSet.insert(type);

        return keepOnlyTypeID(typeSet);

    }  // End of method 'satTypeValueMap::keepOnlyTypeID()'



      // Modifies this object, keeping only these types of data.
      // @param typeSet Set (TypeIDSet) containing the types of data
      //                to be kept.
    satTypeValueMap& satTypeValueMap::keepOnlyTypeID(const TypeIDSet& typeSet)
    {

        satTypeValueMap stvMap( extractTypeID(typeSet) );
        (*this) = stvMap;

        return (*this);

    }  // End of method 'satTypeValueMap::keepOnlyTypeID()'


      // Modifies this object, keeping only this type of data.
      // @param type Type of value to be kept.
    sourceTypeValueMap& sourceTypeValueMap::keepOnlyTypeID(const TypeID& type)
    {

        TypeIDSet typeSet;
        typeSet.insert(type);

        return keepOnlyTypeID(typeSet);

    }  // End of method 'satTypeValueMap::keepOnlyTypeID()'



      // Modifies this object, keeping only these types of data.
      // @param typeSet Set (TypeIDSet) containing the types of data
      //                to be kept.
    sourceTypeValueMap& sourceTypeValueMap::keepOnlyTypeID(const TypeIDSet& typeSet)
    {

        sourceTypeValueMap stvMap( extractTypeID(typeSet) );
        (*this) = stvMap;

        return (*this);

    }  // End of method 'satTypeValueMap::keepOnlyTypeID()'


      // Return a satTypeValueMap with only these types of data.
      // @param typeSet Set (TypeIDSet) containing the types of data
      //                to be extracted.
    sourceTypeValueMap sourceTypeValueMap::extractTypeID(const TypeIDSet& typeSet) const
    {

        sourceTypeValueMap theMap;

        for( sourceTypeValueMap::const_iterator it = (*this).begin();
             it != (*this).end();
             ++it )
        {

            typeValueMap tvMap( (*it).second.extractTypeID(typeSet) );
            if( tvMap.size() > 0 )
            {
                theMap[(*it).first] = tvMap;
            }

        }

        return theMap;

    }  // End of method 'sourceTypeValueMap::extractTypeID()'


      /* Return the data value (double) corresponding to provided SourceID
       * and TypeID.
       *
       * @param source source to be looked for.
       * @param type   Type to be looked for.
       */
    double sourceTypeValueMap::getValue( const SourceID& source,
                                         const TypeID& type ) const
        noexcept(false)
    {

        sourceTypeValueMap::const_iterator itObs( (*this).find(source) );
        if( itObs != (*this).end() )
        {
            return (*itObs).second.getValue( type );
        }
        else
        {
            GPSTK_THROW(SourceIDNotFound("SourceID not found in map"));
        }

    }  // End of method 'sourceTypeValueMap::getValue()'



      // Modifies this object, removing these satellites.
      // @param satSet Set (SatIDSet) containing the satellites
      //               to be removed.
    satTypeValueMap& satTypeValueMap::removeSatID(const SatIDSet& satSet)
    {

        for( SatIDSet::const_iterator pos = satSet.begin();
             pos != satSet.end();
             ++pos )
        {
            (*this).erase(*pos);
        }

        return (*this);

    }  // End of method 'satTypeValueMap::removeSatID()'



      // Modifies this object, removing this type of data.
      // @param type Type of value to be removed.
    satTypeValueMap& satTypeValueMap::removeTypeID(const TypeID& type)
    {

        for( satTypeValueMap::iterator it = (*this).begin();
             it != (*this).end();
             ++it )
        {
            (*it).second.removeTypeID(type);
        }

        return (*this);

    }  // End of method 'satTypeValueMap::removeTypeID()'



      // Modifies this object, removing these types of data.
      // @param typeSet Set (TypeIDSet) containing the types of data
      //                to be kept.
    satTypeValueMap& satTypeValueMap::removeTypeID(const TypeIDSet& typeSet)
    {

        for( TypeIDSet::const_iterator pos = typeSet.begin();
             pos != typeSet.end();
             ++pos )
        {
            removeTypeID(*pos);
        }

        return (*this);

    }  // End of method 'satTypeValueMap::removeTypeID()'



      // Return a GPSTk::Vector containing the data values with this type.
      // @param type Type of value to be returned.
      // This method returns zero if a given satellite does not have this type.
    Vector<double> satTypeValueMap::getVectorOfTypeID(const TypeID& type) const
    {

         // Let's declare a STL vector
        std::vector<double> temp;

        for( satTypeValueMap::const_iterator it = (*this).begin();
             it != (*this).end();
             ++it )
        {

            typeValueMap::const_iterator itObs( (*it).second.find(type) );
            if ( itObs != (*it).second.end() )
            {
                temp.push_back( (*itObs).second );
            }
            else
            {
                temp.push_back( 0.0 );
            }

        }

         // Let's declare a GPSTk Vector
        Vector<double> result;

         // Transform STL vector into GPSTk Vector
        result = temp;

        return result;

    }  // End of method 'satTypeValueMap::getVectorOfTypeID()'


      // Return a GPSTk::Vector containing the data values with this type.
      // @param type Type of value to be returned.
      // This method returns zero if a given satellite does not have this type.
    Vector<double> satTypeValueMap::getVectorOfTypeID(const TypeID& type,
                                                      SatelliteSystem::Systems sys) const
    {

         // Let's declare a STL vector
        std::vector<double> temp;

        for( satTypeValueMap::const_iterator it = (*this).begin();
             it != (*this).end();
             ++it )
        {
            if((*it).first.system == sys)
            {
                typeValueMap::const_iterator itObs( (*it).second.find(type) );
                if ( itObs != (*it).second.end() )
                {
                    temp.push_back( (*itObs).second );
                }
                else
                {
                    temp.push_back( 0.0 );
                }
            }

        }

         // Let's declare a GPSTk Vector
        Vector<double> result;

         // Transform STL vector into GPSTk Vector
        result = temp;

        return result;

    }  // End of method 'satTypeValueMap::getVectorOfTypeID()'


      // Return a GPSTk::Matrix containing the data values in this set.
      // @param typeSet  TypeIDSet of values to be returned.
    Matrix<double> satTypeValueMap::getMatrixOfTypes(const TypeIDSet& typeSet) const
    {

         // First, let's create a Matrix<double> of the proper size
        Matrix<double> tempMat( (*this).numSats(), typeSet.size(), 0.0 );

        size_t numRow(0), numCol(0);

        for( satTypeValueMap::const_iterator it = (*this).begin();
             it != (*this).end();
             ++it )
        {
            numCol=0;

            for( TypeIDSet::const_iterator pos = typeSet.begin();
                 pos != typeSet.end();
                 ++pos )
            {

                typeValueMap::const_iterator itObs( (*it).second.find(*pos) );
                if( itObs != (*it).second.end() )
                {
                    tempMat(numRow, numCol) = (*itObs).second;
                }

                ++numCol;
            }

            ++numRow;

        }

        return tempMat;

    }  // End of method 'satTypeValueMap::getMatrixOfTypes()'


      // Return a GPSTk::Matrix containing the data values in this set.
      // @param typeSet  TypeIDSet of values to be returned.
    Matrix<double> satTypeValueMap::getMatrixOfTypes(const TypeIDSet& typeSet, 
                                                     SatelliteSystem::Systems sys) const
    {

         // First, let's create a Matrix<double> of the proper size
        Matrix<double> tempMat( (*this).numSats(sys), typeSet.size(), 0.0 );

        size_t numRow(0), numCol(0);

        for( satTypeValueMap::const_iterator it = (*this).begin();
             it != (*this).end();
             ++it )
        {
            if((*it).first.system == sys)
            {
                numCol=0;

                for( TypeIDSet::const_iterator pos = typeSet.begin();
                     pos != typeSet.end();
                     ++pos )
                {

                    typeValueMap::const_iterator itObs( (*it).second.find(*pos) );
                    if( itObs != (*it).second.end() )
                    {
                        tempMat(numRow, numCol) = (*itObs).second;
                    }

                    ++numCol;
                }
                ++numRow;
            }
        }

        return tempMat;

    }  // End of method 'satTypeValueMap::getMatrixOfTypes()'



      /* Modifies this object, adding one vector of data with this type,
       * one value per satellite.
       *
       * If type already exists, data is overwritten. If the number of
       * values does not match with the number of satellites, a
       * NumberOfSatsMismatch exception is thrown.
       *
       * Given that dataVector does not store information about the
       * satellites the values correspond to, the user is held responsible
       * for having the data values stored in dataVector in the proper
       * order regarding the SatIDs in this object.
       *
       * @param type          Type of data to be added.
       * @param dataVector    GPSTk Vector containing the data to be added.
       */
    satTypeValueMap& satTypeValueMap::insertTypeIDVector( const TypeID& type,
                                                          const Vector<double> dataVector )
        noexcept(false)
    {

        if( dataVector.size() == (*this).numSats() )
        {
            size_t pos = 0;

            for( satTypeValueMap::iterator it = (*this).begin();
                 it != (*this).end();
                 ++it )
            {
                (*it).second[type] = dataVector[pos];
                ++pos;
            }

            return (*this);

        }
        else
        {
            GPSTK_THROW( NumberOfSatsMismatch(" Number of data values in vector \
and number of satellites do not match") );
        }

    }  // End of method 'satTypeValueMap::insertTypeIDVector()'



      /* Modifies this object, adding a matrix of data, one vector
       * per satellite.
       *
       * If types already exists, data is overwritten. If the number of
       * rows in matrix does not match with the number of satellites, a
       * NumberOfSatsMismatch exception is thrown. If the number of columns
       * in matrix does not match with the number of types in typeSet, a
       * NumberOfTypesMismatch exception is thrown.
       *
       * Given that dataMatrix does not store information about the
       * satellites and types the values correspond to, the user is held
       * responsible for having those data values stored in dataMatrix in
       * the proper order regarding the SatIDs in this object and the
       * provided typeSet.
       *
       * @param typeSet       Set (TypeIDSet) containing the types of data
       *                      to be added.
       * @param dataMatrix    GPSTk Matrix containing the data to be added.
       */
    satTypeValueMap& satTypeValueMap::insertMatrix( const TypeIDSet& typeSet,
                                                    const Matrix<double> dataMatrix )
        noexcept(false)
    {

        if( dataMatrix.rows() != (*this).numSats() )
        {
            GPSTK_THROW( NumberOfSatsMismatch("Number of rows in matrix and \
number of satellites do not match") );
        }

        if( dataMatrix.cols() == typeSet.size() )
        {

            size_t pos(0);

            for( satTypeValueMap::iterator it = (*this).begin();
                 it != (*this).end();
                 ++it )
            {

                size_t idx(0);

                for( TypeIDSet::const_iterator itSet = typeSet.begin();
                     itSet != typeSet.end();
                     ++itSet )
                {
                    (*it).second[(*itSet)] = dataMatrix(pos,idx);
                    ++idx;
                }

                ++pos;

            }

            return (*this);

        }
        else
        {
            GPSTK_THROW( NumberOfTypesMismatch("Number of data values per row \
in matrix and number of types do not match") );
        }

    }  // End of method 'satTypeValueMap::insertMatrix()'



      /* Return the data value (double) corresponding to provided SatID
       * and TypeID.
       *
       * @param satellite     Satellite to be looked for.
       * @param type          Type to be looked for.
       */
    double satTypeValueMap::getValue( const SatID& satellite,
                                      const TypeID& type ) const
        noexcept(false)
    {

        satTypeValueMap::const_iterator itObs( (*this).find(satellite) );
        if( itObs != (*this).end() )
        {
            return (*itObs).second.getValue( type );
        }
        else
        {
            GPSTK_THROW(SatIDNotFound("SatID not found in map"));
        }

    }  // End of method 'satTypeValueMap::getValue()'



      // Return a reference to the typeValueMap with corresponding SatID.
      // @param type Type of value to be looked for.
    typeValueMap& satTypeValueMap::operator()(const SatID& satellite) 
    {

        satTypeValueMap::iterator itObs( (*this).find(satellite) );
        if( itObs != (*this).end() )
        {
            return (*itObs).second;
        }
        else
        {
            cerr << (SatIDNotFound("SatID not found in map"));
        }

    }  // End of method 'satTypeValueMap::operator()'


      /* Return the data value (double) corresponding to provided SatID
       * and TypeID.
       *
       * @param satellite     Satellite to be looked for.
       * @param type          Type to be looked for.
       */
    double systemTypeValueMap::getValue( const SatelliteSystem::Systems& system,
                                         const TypeID& type ) const
        noexcept(false)
    {

        auto itData( (*this).find(system) );
        if( itData != (*this).end() )
        {
            return (*itData).second.getValue( type );
        }
        else
        {
            GPSTK_THROW(SystemNotFound("SatID not found in map"));
        }

    }  // End of method 'satTypeValueMap::getValue()'

      ///
      /// gnss data headders
      ///



      // Assignment operator
   gnssRinexHeader& gnssRinexHeader::operator=(
                                          const gnssRinexHeader& right)
   {

      if ( this == &right )  return (*this); 

     
      epoch       = right.epoch;
      epochFlag   = right.epochFlag;
      source      = right.source; 

      srcAntType  = right.srcAntType;
      srcClock    = right.srcClock;
      srcPos      = right.srcPos;
      srcTide     = right.srcTide;
      srcMonument = right.srcMonument;
      srcAntenna  = right.srcAntenna;

      return (*this);

   }  // End of operator 'gnssRinexHeader::operator=()'



      // Convenience output method for gnssRinexHeader
   std::ostream& gnssRinexHeader::dump(std::ostream& s) const
   {
       s << epoch << " "
         << epochFlag    << " "
         << source       << " "
         << srcAntType   << " "
         << srcClock     << " "
         << srcPos       << " "
         << srcTide      << " "
         << srcMonument  << " "
         << srcAntenna.getAntennaType() << " "
         ;

       return s;

   }  // End of method 'gnssRinexHeader::dump()'



      // stream output for gnssRinexHeader
   std::ostream& operator<<( std::ostream& s,
                             const gnssRinexHeader& grh )
   {

      grh.dump(s);

      return s;

   }  // End of 'operator<<' for gnssRinexHeader

       // Assignment operator
    sourceRinexHeader& sourceRinexHeader::operator=(
                                           const sourceRinexHeader& right)
    {

       if ( this == &right )
       {
          return (*this);
       }

       epoch            = right.epoch;
       sourceSet        = right.sourceSet;

       srcEpochFlagData = right.srcEpochFlagData;
       srcAntTypeData   = right.srcAntTypeData;

       srcClockData     = right.srcClockData;
       srcPosData       = right.srcPosData;
       srcTideData      = right.srcTideData;
       srcMonumentData  = right.srcMonumentData;
       srcAntennaData   = right.srcAntennaData;

       return (*this);

    }  // End of operator 'sourceRinexHeader::operator=()'


      // Convenience output method for sourceRinexHeader
   std::ostream& sourceRinexHeader::dump(std::ostream& s) const
   {
       s << epoch << " " << endl ;

       s << "source :" << endl;
       for(SourceIDSet::const_iterator itsrc = sourceSet.begin();
           itsrc != sourceSet.end();
           ++itsrc)
       {
           s << (*itsrc) << " " << endl ;
       }

       s << "Monument:" << endl;
       for(std::map<SourceID, Triple>::const_iterator itsrc=srcMonumentData.begin();
           itsrc != srcMonumentData.end();
           ++itsrc)
       {
           s << (*itsrc).first << " " << (*itsrc).second << endl;
       }

       s << "tide:" << endl;
       for(std::map<SourceID, Triple>::const_iterator itsrc=srcTideData.begin();
           itsrc != srcTideData.end();
           ++itsrc)
       {
           s << (*itsrc).first << " " << (*itsrc).second << endl;
       }

       s << "antenna:" << endl;
       for(std::map<SourceID, Antenna>::const_iterator itsrc=srcAntennaData.begin();
           itsrc != srcAntennaData.end();
           ++itsrc)
       {
           s << (*itsrc).first << " " << (*itsrc).second.getAntennaType() << endl;
       }


       return s;

   }  // End of method 'sourceRinexHeader::dump()'



       // stream output for sourceRinexHeader
    std::ostream& operator<<( std::ostream& s,
                              const sourceRinexHeader& srh )
    {

       srh.dump(s);
       return s;

    }  // End of 'operator<<' for sourceRinexHeader


      ////// gnssRinex //////


      // Return a gnssRinex with only this satellite.
      // @param satellite Satellite to be extracted.
    gnssRinex gnssRinex::extractSatID(const SatID& satellite) const
    {

        gnssRinex result;
        result.header = (*this).header;
        result.body = (*this).body.extractSatID(satellite);

        return result;

    }  // End of method 'gnssRinex::extractSatID()'



      // Return a gnssRinex with only one satellite, identified
      // by the given parameters.
      // @param p Satellite PRN number.
      // @param p System the satellite belongs to.
    gnssRinex gnssRinex::extractSatID( const int& p,
                                                     const SatelliteSystem::Systems& s ) const
    {

        SatID tempSatellite(p, s);  // We build a temporary SatID object

        return extractSatID(tempSatellite);

    }  // End of method 'gnssRinex::extractSatID()'



      // Return a gnssRinex with only these satellites.
      // @param satSet Set (SatIDSet) containing the satellites
      //               to be extracted.
    gnssRinex gnssRinex::extractSatID(const SatIDSet& satSet) const
    {

        gnssRinex result;
        result.header = (*this).header;
        result.body = (*this).body.extractSatID(satSet);

        return result;

    }  // End of method 'gnssRinex::extractSatID()'



      // Modifies this object, keeping only this satellite.
      // @param satellite Satellite to be kept.
    gnssRinex& gnssRinex::keepOnlySatID(const SatID& satellite)
    {

        SatIDSet satSet;
        satSet.insert(satellite);

        return keepOnlySatID(satSet);

    }  // End of method 'gnssRinex::keepOnlySatID()'



      // Modifies this object, keeping only this satellite.
      // @param p Satellite PRN number.
      // @param p System the satellite belongs to.
    gnssRinex& gnssRinex::keepOnlySatID( const int& p,
                                                       const SatelliteSystem::Systems& s )
    {

        SatID tempSatellite(p, s);  // We build a temporary SatID object

        return keepOnlySatID(tempSatellite);

    }  // End of method 'gnssRinex::keepOnlySatID()'



      // Modifies this object, keeping only these satellites.
      // @param satSet Set (SatIDSet) containing the satellites to be kept.
    gnssRinex& gnssRinex::keepOnlySatID(const SatIDSet& satSet)
    {

        satTypeValueMap stvMap( (*this).body.extractSatID(satSet) );
        (*this).body = stvMap;

        return (*this);

    }  // End of method 'gnssRinex::keepOnlySatID()'



      // Return a gnssRinex with only this type of data.
      // @param type Type of value to be extracted.
    gnssRinex gnssRinex::extractTypeID(const TypeID& type) const
    {

        gnssRinex result;
        result.header = (*this).header;
        result.body = (*this).body.extractTypeID(type);

        return result;

    }  // End of method 'gnssRinex::extractTypeID()'



      // Return a gnssRinex with only these types of data.
      // @param typeSet Set (TypeIDSet) containing the types of data
      //                to be extracted.
    gnssRinex gnssRinex::extractTypeID(const TypeIDSet& typeSet) const
    {

        gnssRinex result;
        result.header = (*this).header;
        result.body = (*this).body.extractTypeID(typeSet);

        return result;

    }  // End of method 'gnssRinex::extractTypeID()'



      // Modifies this object, keeping only this type of data.
      // @param type Type of value to be kept.
    gnssRinex& gnssRinex::keepOnlyTypeID(const TypeID& type)
    {

        TypeIDSet typeSet;
        typeSet.insert(type);

        return keepOnlyTypeID(typeSet);

    }  // End of method 'gnssRinex::keepOnlyTypeID()'



      // Modifies this object, keeping only these types of data.
      // @param typeSet Set (TypeIDSet) containing the types of data
      //                to be kept.
    gnssRinex& gnssRinex::keepOnlyTypeID(const TypeIDSet& typeSet)
    {

        satTypeValueMap stvMap( (*this).body.extractTypeID(typeSet) );
        (*this).body = stvMap;

        return (*this);

    }  // End of method 'gnssRinex::keepOnlyTypeID()'



      // Modifies this object, removing these satellites.
      // @param satSet Set (SatIDSet) containing the satellites
      //               to be removed.
    gnssRinex& gnssRinex::removeSatID(const SatIDSet& satSet)
    {

        for( SatIDSet::const_iterator pos = satSet.begin();
             pos != satSet.end();
             ++pos )
        {
            (*this).body.erase(*pos);
        }

        return (*this);

    }  // End of method 'gnssRinex::removeSatID()'



      // Modifies this object, removing these types of data
      // @param typeSet Set (TypeIDSet) containing the types of data
      //                to be kept.
    gnssRinex& gnssRinex::removeTypeID(const TypeIDSet& typeSet)
    {

        for( TypeIDSet::const_iterator pos = typeSet.begin();
             pos != typeSet.end();
             ++pos )
        {
            (*this).body.removeTypeID(*pos);
        }

        return (*this);

    }  // End of method 'gnssRinex::removeTypeID()'




      // Return a gnssRinex with only these types of data.
      // @param satSys Satellite System value to be kept.
    gnssRinex& gnssRinex::keepOnlySatSystem(const SatelliteSystem::Systems satSys)
    {
        satTypeValueMap stvMap( (*this).body );

        SatIDSet satRejectedSet;
        for(satTypeValueMap::iterator it = stvMap.begin();
            it != stvMap.end();
            ++it)
        {
            if( it->first.system != satSys ) satRejectedSet.insert( it->first );
        }
        stvMap.removeSatID(satRejectedSet);


        (*this).body = stvMap;

        return (*this);

    }  // End of method 'gnssRinex::keepOnlySatSystem()'



      //// Some other handy data structures



      /* Return the data value (double) corresponding to provided SourceID,
       * SatID and TypeID.
       *
       * @param source        Source to be looked for.
       * @param satellite     Satellite to be looked for.
       * @param type          Type to be looked for.
       */
    double sourceDataMap::getValue( const SourceID& source,
                                    const SatID& satellite,
                                    const TypeID& type ) const
        noexcept(false)
    {

         // Look for the SourceID
        sourceDataMap::const_iterator itObs( (*this).find(source) );
        if( itObs != (*this).end() )
        {
            return (*itObs).second.getValue( satellite, type );
        }
        else
        {
            GPSTK_THROW(SourceIDNotFound("SourceID not found in map"));
        }

    }  // End of method 'sourceDataMap::getValue()'



      /* Get a set with all the SourceID's in this data structure.
       *
       * @warning If current 'sourceDataMap' is big, this could be a very
       * costly operation.
       */
    SourceIDSet sourceDataMap::getSourceIDSet( void ) const
    {

         // SourceID set to be returned
        SourceIDSet toReturn;

         // Then, iterate through corresponding 'sourceDataMap'
        for(sourceDataMap::const_iterator sdmIter = (*this).begin();
            sdmIter != (*this).end();
            ++sdmIter)
        {

            // Add current SourceID to 'toReturn'
            toReturn.insert( (*sdmIter).first );

        }  // End of 'for( sourceDataMap::const_iterator sdmIter = ...'

        return toReturn;

    }  // End of method 'sourceDataMap::getSourceIDSet()'



      /* Get a set with all the SatID's in this data structure.
       *
       * @warning If current 'sourceDataMap' is big, this could be a very
       * costly operation.
       */
    SatIDSet sourceDataMap::getSatIDSet( void ) const
    {

         // SatID set to be returned
        SatIDSet toReturn;

         // Then, iterate through corresponding 'sourceDataMap'
        for(sourceDataMap::const_iterator sdmIter = (*this).begin();
            sdmIter != (*this).end();
            ++sdmIter)
        {

            // Finally, iterate through corresponding 'satTypeValueMap'
            for(satTypeValueMap::const_iterator stvmIter =
                                                   (*sdmIter).second.begin();
                stvmIter != (*sdmIter).second.end();
                stvmIter++)
            {

                // Add current SatID to 'toReturn'
                toReturn.insert( (*stvmIter).first );

            }  // End of 'for( satTypeValueMap::const_iterator stvmIter = ...'

        }  // End of 'for( sourceDataMap::const_iterator sdmIter = ...'

        return toReturn;

    }  // End of method 'sourceDataMap::getSatIDSet()'



      /* Adds 'gnssRinex' object data to this structure.
       *
       * @param gRin     gnssRinex object containing data to be added.
       */
    sourceRinex& sourceRinex::addGnssRinex( const gnssRinex& gRin )
    {

        (*this).body.insert( pair<SourceID, satTypeValueMap>( gRin.header.source, gRin.body)) ;

        (*this).header.epoch = gRin.header.epoch;

        (*this).header.sourceSet.insert(gRin.header.source);

        (*this).header.srcEpochFlagData[gRin.header.source]   = gRin.header.epochFlag;
        (*this).header.srcAntTypeData[gRin.header.source]     = gRin.header.srcAntType;
        (*this).header.srcClockData[gRin.header.source]       = gRin.header.srcClock;
        (*this).header.srcPosData[gRin.header.source]         = gRin.header.srcPos;
        (*this).header.srcTideData[gRin.header.source]        = gRin.header.srcTide;
        (*this).header.srcMonumentData[gRin.header.source]    = gRin.header.srcMonument;
        (*this).header.srcAntennaData[gRin.header.source]     = gRin.header.srcAntenna;

         // Return current GDS.
        return (*this);

    }  // End of method 'sourceRinex::addGnssRinex()'



      /* Return a 'gnssRinex' object corresponding to given SourceID.
       *
       * @param source     SourceID object.
       *
       * @warning Returned data will correspond to first matching SourceID,
       * if it exists.
       */
    gnssRinex sourceRinex::getGnssRinex( const SourceID& source ) const
    {

         // Declare a gnssRinex object to be returned
        gnssRinex toReturn;

        sourceDataMap sdMap;

        sdMap = (*this).body;

         // We'll need a flag
        bool found(false);


        // Look for SourceID
        SourceIDSet::const_iterator itSrc( (*this).header.sourceSet.find( source ) );
        if( itSrc != (*this).header.sourceSet.end() )
        {
            toReturn.header = (*this).header.getGnssRinexHeader(source);
            found = true;
        }


        // Look for SourceID
        sourceDataMap::const_iterator iter( sdMap.find( source ) );
        if( iter != sdMap.end() )
        {
            toReturn.body = (*iter).second;
            found = true;
        }

        if( !found )
        {
            GPSTK_THROW(SourceIDNotFound("source not found"));
        }


         // Return GDS
        return toReturn;

    }  // End of method 'sourceRinex::getGnssRinex()'


      /* Return the data value (double) corresponding to the first epoch
       * in the data structure, given SourceID, SatID and TypeID.
       *
       * @param source        Source to be looked for.
       * @param satellite     Satellite to be looked for.
       * @param type          Type to be looked for.
       *
       * @warning If within first epoch (epoch +/- tolerance) more than one
       * match exists, then only the first one is returned.
       */
    double sourceRinex::getValue( const SourceID& source,
                                  const SatID& satellite,
                                  const TypeID& type ) const
        noexcept(false)
    {
         // Value to be returned
        double toReturn;


        sourceDataMap sdMap( (*this).body );

        toReturn = sdMap.getValue(source, satellite, type);

        return toReturn;

    }  // End of method 'sourceRinex::getValue()'


      /* Inserts a data value (double) in the first epoch of the data
       * structure with the given SourceID, SatID and TypeID.
       *
       * @param source        Source to be looked for.
       * @param satellite     Satellite to be looked for.
       * @param type          Type of the new data.
       * @param value         Value to be inserted.
       */
    sourceRinex& sourceRinex::insertValue( const SourceID& source,
                                           const SatID& satellite,
                                           const TypeID& type,
                                           double value )
        noexcept(false)
    {

         // We'll need a flag
        bool found(false);

        sourceDataMap sdMap( (*this).body );

        // Look for the source
        sourceDataMap::iterator it( sdMap.find(source) );

        if( it != sdMap.end() )
        {
            // Look for the satellite
            satTypeValueMap::iterator it2( (*it).second.find(satellite) );

            if( it2 != (*it).second.end() )
            {
                // Insert type and value
                (*it2).second[ type ] = value;

                // Work is done, let's get out
                found = true;

            }  // End of 'if( it3 != (*it2).second.end() )'

        }  // End of 'if( it2 != (*it).second.end() )'

         // Check if we found a proper place to insert value
        if( !found )
        {
            GPSTK_THROW( ValueNotFound("No proper place to insert value"));
        }

        return (*this);

    }  // End of method 'sourceRinex::insertValue()'



      /* Get a set with all the SourceID's in this data structure.
       *
       * @warning If current 'sourceRinex' is big, this could be a very
       * costly operation.
       */
    SourceIDSet sourceRinex::getSourceIDSet( void ) const
    {

         // SourceID set to be returned
        SourceIDSet toReturn;

        sourceDataMap sdMap( (*this).body );

         // Iterate through all items in the sourceRinex
        for(sourceDataMap::const_iterator it = sdMap.begin();
            it != sdMap.end();
            ++it)
        {
           // Add current SourceID to 'toReturn'
           toReturn.insert( (*it).first );

        }  // End of 'for( sourceRinex::const_iterator it = gdMap.begin(); ...'

        return toReturn;

    }  // End of method 'sourceRinex::getSourceIDSet()'


      /* Get a set with all the SatID's in this data structure.
       *
       * @warning If current 'sourceRinex' is big, this could be a very
       * costly operation.
       */
    SatIDSet sourceRinex::getSatIDSet( void ) const
    {

         // SatID set to be returned
        SatIDSet toReturn;

        sourceDataMap sdMap( (*this).body );

        // Then, iterate through corresponding 'sourceDataMap'
        for(sourceDataMap::const_iterator sdmIter = sdMap.begin();
            sdmIter != sdMap.end();
            ++sdmIter)
        {

            // Finally, iterate through corresponding 'satTypeValueMap'
            for(satTypeValueMap::const_iterator stvmIter =
                                                  (*sdmIter).second.begin();
                stvmIter != (*sdmIter).second.end();
                ++stvmIter)
            {

                // Add current SatID to 'toReturn'
                toReturn.insert( (*stvmIter).first );

            }  // End of 'for( satTypeValueMap::const_iterator stvmIter = ...'

        }  // End of 'for( sourceDataMap::const_iterator sdmIter = ...'

        return toReturn;

    }  // End of method 'sourceRinex::getSatIDSet()'



      // Convenience output method
    std::ostream& sourceRinex::dump( std::ostream& s, int mode ) const
    {

        // Declare a 'YDSTime' object to ease printing
        YDSTime time( (*this).header.epoch);

        s << setprecision(12) ;

        // First, print year, Day-Of-Year and Seconds of Day
        s << time.year << " "
          << time.doy << " "
          << time.sod << " ";

        sourceDataMap sdMap( (*this).body );

        // Then, iterate through corresponding 'sourceDataMap'
        for(sourceDataMap::const_iterator sdmIter = sdMap.begin();
            sdmIter != sdMap.end();
            ++sdmIter)
        {

            // Finally, iterate through corresponding 'satTypeValueMap'
            for(satTypeValueMap::const_iterator stvmIter =
                                                  (*sdmIter).second.begin();
                stvmIter != (*sdmIter).second.end();
                ++stvmIter)
            {

                // Second, print SourceID information
                s << (*sdmIter).first << " ";

                // Third, print satellite (system and PRN)
                s << (*stvmIter).first << " ";

                // Fourth, print type descriptions and numerical values
                for(typeValueMap::const_iterator itObs =
                                               (*stvmIter).second.begin();
                    itObs != (*stvmIter).second.end();
                    ++itObs)
                {

                    s << (*itObs).first << " "
                      << (*itObs).second << " ";

                }  // End of 'for( typeValueMap::const_iterator itObs = ...'

                // Add end-of-line
                s << endl;

            }  // End of 'for( satTypeValueMap::const_iterator stvmIter = ...'

        }  // End of 'for( sourceDataMap::const_iterator sdmIter = ...'

         // Let's return the 'std::ostream'
        return s;

    }  // End of method 'sourceRinex::dump()'



      // Return a sourceRinex with only this source.
      // @param source Source to be extracted.
    sourceRinex sourceRinex::extractSourceID(const SourceID& source)
    {
        SourceIDSet sourceSet;
        sourceSet.insert(source);

        return extractSourceID(sourceSet);

    }  // End of method 'sourceRinex::extractSourceID()'



      /// Return a sourceRinex with only these sources.
      /// @param sourceSet Set(SourceIDSet) containing the sources
      ///                  to be extracted.
    sourceRinex sourceRinex::extractSourceID(const SourceIDSet& sourceSet)
    {
        const sourceDataMap sourceData( (*this).body );
        sourceDataMap tempSourceData;

        for(sourceDataMap::const_iterator itsrc = sourceData.begin();
            itsrc != sourceData.end();
            ++itsrc)
        {
            SourceIDSet::const_iterator itsrc2 = sourceSet.find(itsrc->first);
            if(itsrc2!=sourceSet.end())
            {
                tempSourceData.insert( make_pair((*itsrc).first, (*itsrc).second) );
            }

        }  // loop in the sources

        (*this).body = tempSourceData;

        return (*this);

    }  // End of method 'sourceRinex::extractSourceID()'


      // Modifies this object, keeping only this source.
      // @param source Source to be extracted.
    sourceRinex& sourceRinex::keepOnlySourceID(const SourceID& source)
    {
        (*this) = extractSourceID(source);
        return (*this);
    }


      // Modifies this object, keeping only these sources.
      // @param sourceSet Set(SourceIDSet) containing the sources
      //                  to be extracted.
    sourceRinex& sourceRinex::keepOnlySourceID(const SourceIDSet& sourceSet)
    {
        (*this) = extractSourceID(sourceSet);
        return (*this);
    }


      // Modifies this object, removing this source.
      // @param source Source to be removed.
    sourceRinex& sourceRinex::removeSourceID(const SourceID& source)
    {
        SourceIDSet sourceSet;
        sourceSet.insert(source);

        return removeSourceID(sourceSet);
    }


      // Modifies this object, keeping only these sources.
      // @param sourceSet Set(SourceIDSet) containing the sources
      //                  to be removed.
    sourceRinex& sourceRinex::removeSourceID(const SourceIDSet& sourceSet)
    {

        sourceDataMap sourceData( (*this).body );
        sourceDataMap tempSourceData;

        for(sourceDataMap::const_iterator itsrc = sourceData.begin();
            itsrc != sourceData.end();
            ++itsrc)
        {
            SourceIDSet::const_iterator itsrc2 = sourceSet.find(itsrc->first);
            if(itsrc2==sourceSet.end())
            {
                tempSourceData.insert( make_pair((*itsrc).first, (*itsrc).second) );
            }

        }  // loop in the sources

        (*this).body = tempSourceData;


        return (*this);

    }  // End of method 'sourceRinex::removeSourceID()'


      // Return a sourceRinex with only this satellite.
      // @param sat Satellite to be extracted.
    sourceRinex sourceRinex::extractSatID(const SatID& sat)
    {
        SatIDSet satSet;
        satSet.insert(sat);

        return extractSatID(satSet);
    }


      // Return a sourceRinex with only these satellites.
      // @param satSet Set(SatIDSet) containing the satellite
      //               to be extracted.
    sourceRinex sourceRinex::extractSatID(const SatIDSet& satSet)
    {
        sourceDataMap sourceData( (*this).body );
        sourceDataMap tempSourceData;

        for(sourceDataMap::const_iterator itsrc = sourceData.begin();
            itsrc != sourceData.end();
            ++itsrc)
        {
            satTypeValueMap stvData( (*itsrc).second );
            stvData.keepOnlySatID(satSet);
            tempSourceData.insert(make_pair( (*itsrc).first, stvData) );

        }  // loop in the sources

        (*this).body = tempSourceData;

        return (*this);

    }  // End of method 'sourceRinex::extractSatID()'


      // Modifies this object, keeping only this satellite.
      // @param sat Satellite to be extracted.
    sourceRinex& sourceRinex::keepOnlySatID(const SatID& sat)
    {
        (*this) = extractSatID(sat);
        return (*this);
    }


      // Modifies this object, keeping only these satellites.
      // @param satSet Set(SatIDSet) containing the satellite
      //                  to be extracted.
    sourceRinex& sourceRinex::keepOnlySatID(const SatIDSet& satSet)
    {
        (*this) = extractSatID(satSet);
        return (*this);
    }


      // Modifies this object, removing this satellite.
      // @param sat Satellite to be removed.
    sourceRinex& sourceRinex::removeSatID(const SatID& sat)
    {
        SatIDSet satSet;
        satSet.insert(sat);

        return removeSatID(satSet);
    }


      // Modifies this object, keeping only these satellites.
      // @param satSet Set(SatIDSet) containing the satellites
      //               to be removed.
    sourceRinex& sourceRinex::removeSatID(const SatIDSet& satSet)
    {
        sourceDataMap sourceData( (*this).body );
        sourceDataMap tempSourceData;

        for(sourceDataMap::const_iterator itsrc = sourceData.begin();
            itsrc != sourceData.end();
            ++itsrc)
        {
            satTypeValueMap stvData( (*itsrc).second );
            stvData.removeSatID(satSet);
            tempSourceData.insert(make_pair( (*itsrc).first, stvData) );

        }  // loop in the sources

        (*this).body = tempSourceData;

        return (*this);

    }  // End of method 'sourceRinex::removeSatID()'


      // Modifies this object, removing this satellite from this source.
      // @param source Source to be removed.
      // @param sat Satellite to be removed.
    sourceRinex& sourceRinex::removeSatID( const SourceID& source,
                                           const SatID& sat )
    {

        sourceDataMap::iterator sdmIter = (*this).body.find( source );

        if( (*this).body.end() != sdmIter )
        {
            sdmIter->second.removeSatID(sat);
        }

    }  // End of method 'sourceRinex::removeSatID()'


      /// Return a sourceRinex with only this type.
      /// @param type Type to be extracted.
    sourceRinex sourceRinex::extractTypeID(const TypeID& type)
    {
        TypeIDSet typeSet;
        typeSet.insert(type);

        return extractTypeID(typeSet);
    }


      // Return a sourceRinex with only these satellites.
      // @param typeSet Set(TypeIDSet) containing the types
      //               to be extracted.
    sourceRinex sourceRinex::extractTypeID(const TypeIDSet& typeSet)
    {
        sourceDataMap sourceData( (*this).body );
        sourceDataMap tempSourceData;

        for(sourceDataMap::const_iterator itsrc = sourceData.begin();
            itsrc != sourceData.end();
            ++itsrc)
        {
            satTypeValueMap stvData( (*itsrc).second );
            stvData.keepOnlyTypeID(typeSet);
            tempSourceData.insert(make_pair( (*itsrc).first, stvData) );

        }  // loop in the sources

        (*this).body = tempSourceData;

        return (*this);
    }


      // Modifies this object, keeping only this type.
      // @param type Type to be extracted.
    sourceRinex& sourceRinex::keepOnlyTypeID(const TypeID& type)
    {
        (*this) = extractTypeID(type);
        return (*this);
    }


      // Modifies this object, keeping only these types.
      // @param typeSet Set(TypeIDSet) containing the type
      //                  to be extracted.
    sourceRinex& sourceRinex::keepOnlyTypeID(const TypeIDSet& typeSet)
    {
        (*this) = extractTypeID(typeSet);
        return (*this);
    }


      // Modifies this object, removing this type.
      // @param type Type to be removed.
    sourceRinex& sourceRinex::removeTypeID(const TypeID& type)
    {
        TypeIDSet typeSet;
        typeSet.insert(type);

        return removeTypeID(typeSet);
    }


      // Modifies this object, remove these types.
      // @param typeSet Set(TypeIDSet) containing the types
      //               to be removed.
    sourceRinex& sourceRinex::removeTypeID(const TypeIDSet& typeSet)
    {
        sourceDataMap sourceData( (*this).body );
        sourceDataMap tempSourceData;

        for(sourceDataMap::const_iterator itsrc = sourceData.begin();
            itsrc != sourceData.end();
            ++itsrc)
        {
            satTypeValueMap stvData( (*itsrc).second );
            stvData.removeTypeID(typeSet);
            tempSourceData.insert(make_pair( (*itsrc).first, stvData) );

        }  // loop in the sources

        (*this).body = tempSourceData;

        return (*this);

    }  // End of method 'sourceRinex::removeTypeID()'


     /// Modifies this object, remove this satellite of this source
     /// and this satellite.
     /// @param source  Source to be removed.
     /// @param sat     Satellite to be removed.
     /// @param type    Type to be removed.
    sourceRinex& sourceRinex::removeTypeID(const SourceID& source,
                                           const SatID& sat,
                                           const TypeID& type)
    {

        const sourceDataMap sourceData( (*this).body );
        sourceDataMap tempSourceData;

        for(sourceDataMap::const_iterator itsrc = sourceData.begin();
            itsrc != sourceData.end();
            ++itsrc)
        {
            satTypeValueMap stvData( (*itsrc).second );
            if(itsrc->first == source)
            {
                for(satTypeValueMap::iterator itsat = stvData.begin();
                    itsat != stvData.end();
                    ++itsat)
                {
                    if(itsat->first == sat)
                    {
                        itsat->second.erase(type);
                    }
                }
            }
            tempSourceData.insert(make_pair( (*itsrc).first, stvData) );

        }  // loop in the sources


        (*this).body = tempSourceData;

        return (*this);

    }  // End of method 'sourceRinex::removeTypeID()'

      // Return a gnssRinex with only these types of data.
      // @param satSys Satellite System value to be kept.
    sourceRinex& sourceRinex::keepOnlySatSystem(const SatelliteSystem::Systems satSys)
    {
        sourceDataMap sData( (*this).body );

        for(sourceDataMap::iterator sdIt = sData.begin();
            sdIt != sData.end();
            sdIt ++)
        {
            SatIDSet satRejectedSet;
            satTypeValueMap stvData(sdIt->second);
            for(satTypeValueMap::iterator it = stvData.begin();
                it != stvData.end();
                ++it)
            {
                if( it->first.system != satSys ) satRejectedSet.insert( it->first );
            }
            stvData.removeSatID(satRejectedSet);

               // store stvData for satSys
            sData[sdIt->first] = stvData;
        }

        (*this).body = sData;

        return (*this);

    }  // End of method 'gnssRinex::keepOnlySatSystem()'



      ////// Other stuff //////


      // Convenience output method for structure satTypeValueMap
    std::ostream& satTypeValueMap::dump( std::ostream& s, int mode ) const
    {

        for(satTypeValueMap::const_iterator it = (*this).begin();
            it != (*this).end();
            ++it)
        {

            // First, print satellite (system and PRN)
            s << (*it).first << " ";

            for(typeValueMap::const_iterator itObs = (*it).second.begin();
                itObs != (*it).second.end();
                ++itObs)
            {

                if (mode==1)
                {
                    s << (*itObs).first << " ";
                }

                s << setprecision(12) ;
                s << (*itObs).second << " ";

            }  // End of 'for( typeValueMap::const_iterator itObs = ...'

            s << endl;

        }  // End of 'for( satTypeValueMap::const_iterator it = ...'

         // Let's return the 'std::ostream'
        return s;

    }  // End of method 'satTypeValueMap::dump()'

      // Convenience output method for structure satTypeValueMap
    std::ostream& gnssRinex::dump( std::ostream& s, int mode ) const
    {
	    s << (*this).header.source << " ";
	    s << (*this).header.epoch << endl;;

	    (*this).body.dump(s, mode);

	    return s;
    }  // End of method 'satTypeValueMap::dump()'

      // stream output for satTypeValueMap
    std::ostream& operator<<( std::ostream& s, const typeValueMap& tvMap )
    {

        tvMap.dump(s,1);
        return s;

    }  // End of 'operator<<'

      // stream output for satTypeValueMap
    std::ostream& operator<<( std::ostream& s, const satValueMap& svMap )
    {

        svMap.dump(s,1);
        return s;

    }  // End of 'operator<<'


      // stream output for satTypeValueMap
    std::ostream& operator<<( std::ostream& s, const satTypeValueMap& stvMap )
    {

        stvMap.dump(s,1);
        return s;

    }  // End of 'operator<<'



      // stream output for sourceRinex
    std::ostream& operator<<( std::ostream& s, const sourceRinex& gRinMap )
    {

        gRinMap.dump(s);
        return s;

    }  // End of 'operator<<'

      // stream output for gnssRinex() 
    std::ostream& operator<<( std::ostream& s, const gnssRinex& f)
    {

        f.dump(s);
        return s;

    }  // End of 'operator<<'


      // Stream input for gnssRinex
    std::istream& operator>>( std::istream& i, gnssRinex& f )
    {
/*
        if( RinexObsStream::isRinexObsStream(i) )       // Rinex2
        {
            try
            {
                RinexObsStream& strm = dynamic_cast<RinexObsStream&>(i);

                if(!strm.headerRead) strm >> strm.header;

                RinexObsHeader& roh = strm.header;

                RinexObsData rod;
                strm >> rod;

//              f.header.source.type = SatIDsystem2SourceIDtype(roh.system);
                // shjzhang 
                // see class:NetworkObsStreams, SourceListReader
                // the type must be consistent
                f.header.source.type = SourceID::Mixed;
                f.header.source.sourceName = StringUtils::upperCase( roh.markerName.substr(0,4) );

                f.header.srcAntType   = roh.antType;
                f.header.srcPos       = roh.antennaPosition;
                f.header.srcMonument  = roh.antennaDeltaHEN;

                f.header.epochFlag    = rod.epochFlag;
                f.header.epoch        = rod.time;


                f.body = satTypeValueMapFromRinexObsData(roh, rod);

                return i;
            }
            catch(...)
            {
                return i;
            }
        }

*/
        if( Rinex3ObsStream::isRinex3ObsStream(i) )     // Rinex3
        {
            Rinex3ObsStream& strm = dynamic_cast<Rinex3ObsStream&>(i);

            // If the header hasn't been read, read it...
            if(!strm.headerRead) strm >> strm.header;

            // Clear out this object
            Rinex3ObsHeader& roh = strm.header;

            Rinex3ObsData rod;
            strm >> rod;

            // Fill data

            // from rinex header
            f.header.source.type = SourceID::Mixed;

            // rinex 2.1
            f.header.source.sourceName = StringUtils::upperCase( roh.markerName.substr(0,4) );

            // rinex 2.1/2.2
            f.header.source.sourceName = StringUtils::upperCase( strip(roh.markerName) );

            f.header.srcAntType        = roh.antType;
            f.header.srcPos            = roh.antennaPosition;
            f.header.srcMonument       = roh.antennaDeltaHEN;

            // from rinex obs data
            f.header.epochFlag         = rod.epochFlag;
            f.header.epoch             = rod.time;


            f.body = satTypeValueMapFromRinex3ObsData(roh, rod);

            return i;
        }

    }  // End of stream input for gnssRinex



      // Convenience function to convert from SatID system to SourceID type.
      // @param sid Satellite ID.
    SourceID::SourceType SatIDsystem2SourceIDtype(const SatID& sid)
    {

         // Select the right system the data came from
        switch(sid.system)
        {
            case SatelliteSystem::GPS:
                return SourceID::GPS;
                break;
            case SatelliteSystem::GLONASS:
                return SourceID::GLONASS;
                break;
            case SatelliteSystem::Galileo:
                return SourceID::Galileo;
                break;
            case SatelliteSystem::SBAS:
                return SourceID::SBAS;
                break;
            case SatelliteSystem::QZSS:
                return SourceID::QZSS;
                break;
            case SatelliteSystem::BDS:
                return SourceID::BDS;
                break;
            case SatelliteSystem::IRNSS:
                return SourceID::IRNSS;
                break;
            case SatelliteSystem::Mixed:
                return SourceID::Mixed;
                break;
            default:
                return SourceID::Unknown;
        }

    } // End SatIDsystem2SourceIDtype(const SatID& sid)

/*
      // Convenience function to fill a satTypeValueMap with data
      // from RinexObsData.
      // @param roh RinexObsHeader holding the data
      // @param rod RinexObsData holding the data.
    satTypeValueMap satTypeValueMapFromRinexObsData(const RinexObsHeader& roh,
                                                    const RinexObsData& rod)
    {
        // We need to declare a satTypeValueMap
        satTypeValueMap theMap;

        RinexObsData::RinexSatMap::const_iterator it;
        for(RinexObsData::RinexSatMap::const_iterator it = rod.obs.begin();
            it != rod.obs.end();
            ++it)
        {
            RinexObsData::RinexObsTypeMap otmap = (*it).second;
            SatID sat = (*it).first;

            typeValueMap tvMap;

            for(RinexObsData::RinexObsTypeMap::const_iterator itObs = otmap.begin();
                itObs != otmap.end();
                ++itObs)
            {
                SatID rsat(sat.id,sat.system);

                TypeID type = ConvertToTypeID( itObs->first, rsat );

                const bool isPhase = IsCarrierPhase( itObs->first );
                const int n = GetCarrierBand( itObs->first );

                if(isPhase)
                {
                    if( (*itObs).second.data == 0.0 ) continue;

                    tvMap[ type ] = (*itObs).second.data*getWavelength(rsat,n);
//
//                  tvMap[ type ] = (*itObs).second.data;     // for debug
//
                    if(n == 1)
                    {
                        tvMap[TypeID::LLI1] = (*itObs).second.lli;
                        tvMap[TypeID::SSI1] = (*itObs).second.ssi;
                    }
                    else if(n == 2)
                    {
                        tvMap[TypeID::LLI2] = (*itObs).second.lli;
                        tvMap[TypeID::SSI2] = (*itObs).second.ssi;
                    }
                    else if(n == 3)
                    {
                        tvMap[TypeID::LLI3] = (*itObs).second.lli;
                        tvMap[TypeID::SSI3] = (*itObs).second.ssi;
                    }
                    else if(n == 5)
                    {
                        tvMap[TypeID::LLI5] = (*itObs).second.lli;
                        tvMap[TypeID::SSI5] = (*itObs).second.ssi;
                    }
                    else if(n == 6)
                    {
                        tvMap[TypeID::LLI6] = (*itObs).second.lli;
                        tvMap[TypeID::SSI6] = (*itObs).second.ssi;
                    }
                    else if(n == 7)
                    {
                        tvMap[TypeID::LLI7] = (*itObs).second.lli;
                        tvMap[TypeID::SSI7] = (*itObs).second.ssi;
                    }
                    else if(n == 8)
                    {
                        tvMap[TypeID::LLI8] = (*itObs).second.lli;
                        tvMap[TypeID::SSI8] = (*itObs).second.ssi;
                    }
                }
                else
                {
                    if( (*itObs).second.data == 0.0 ) continue;

                    tvMap[ type ] = (*itObs).second.data;
                }
            }

            theMap[sat] = tvMap;

        }   // End loop over all the satellite

        return theMap;

    }
*/


      // Convenience function to fill a satTypeValueMap with data
      // from Rinex3ObsData.
      // @param roh Rinex3ObsHeader holding the data
      // @param rod Rinex3ObsData holding the data.
    satTypeValueMap satTypeValueMapFromRinex3ObsData(const Rinex3ObsHeader& roh,
                                                     const Rinex3ObsData& rod)
    {

        // We need to declare a satTypeValueMap
        satTypeValueMap theMap;

        for(Rinex3ObsData::DataMap::const_iterator it = rod.obs.begin();
            it != rod.obs.end();
            ++it)
        {
            SatID sat(it->first);

            typeValueMap tvMap;


            map<std::string,std::vector<RinexObsID> > mapObsTypes(roh.mapObsTypes);
            const vector<RinexObsID> types = mapObsTypes[sat.toString().substr(0,1)];

            for(size_t i=0; i<types.size(); i++)
            {
                TypeID type = ConvertToTypeID(types[i],sat);


                const int n = GetCarrierBand(types[i]);


                if(types[i].type == ObsID::otC)         // Range
                {
                    if(it->second[i].data == 0.0) continue;

                    tvMap[ type ] = it->second[i].data;
                }
                else if(types[i].type == ObsID::otL)    // Phase
                {
                    if(it->second[i].data == 0.0) continue;

                    if(getWavelength(sat,n) == 0.0) continue; 

                    tvMap[type] = it->second[i].data*getWavelength(sat,n);

                    // n=1 2 5 6 7 8 9
                    if(n == 1)
                    {
                        tvMap[TypeID::LLI1] = it->second[i].lli;
                        tvMap[TypeID::SSI1] = it->second[i].ssi;
                    }
                    else if(n == 2)
                    {
                        tvMap[TypeID::LLI2] = it->second[i].lli;
                        tvMap[TypeID::SSI2] = it->second[i].ssi;
                    }
                    else if(n == 3)
                    {
                        tvMap[TypeID::LLI3] = it->second[i].lli;
                        tvMap[TypeID::SSI3] = it->second[i].ssi;
                    }
                    else if(n == 5)
                    {
                        tvMap[TypeID::LLI5] = it->second[i].lli;
                        tvMap[TypeID::SSI5] = it->second[i].ssi;
                    }
                    else if(n == 6)
                    {
                        tvMap[TypeID::LLI6] = it->second[i].lli;
                        tvMap[TypeID::SSI6] = it->second[i].ssi;
                    }
                    else if(n == 7)
                    {
                        tvMap[TypeID::LLI7] = it->second[i].lli;
                        tvMap[TypeID::SSI7] = it->second[i].ssi;
                    }
                    else if(n == 8)
                    {
                        tvMap[TypeID::LLI8] = it->second[i].lli;
                        tvMap[TypeID::SSI8] = it->second[i].ssi;
                    }
                    else if(n == 9)
                    {
                        tvMap[TypeID::LLI9] = it->second[i].lli;
                        tvMap[TypeID::SSI9] = it->second[i].ssi;
                    }
                }
                else
                {
                    tvMap[ type ] = it->second[i].data;
                }
            }

            theMap[sat] = tvMap;

        }   // End loop over all the satellite


        return theMap;

    }


   // Stream output for gnssRinex
   Rinex3ObsStream& operator<<( Rinex3ObsStream& s, gnssRinex& f )
   {
      try
      {
             // Clear out this object
         Rinex3ObsHeader& hdr = s.header;
         Rinex3ObsData rod;

         rod.time = f.header.epoch;
         rod.epochFlag = f.header.epochFlag;
         rod.numSVs = f.numSats();
         rod.clockOffset = 0.0;
         rod.auxHeader = hdr;

         SatIDSet satSet = f.getSatID();
         for(SatIDSet::const_iterator itSat = satSet.begin();
            itSat != satSet.end();
            ++itSat)
         {
             SatID sat = (*itSat);

             cout << "sat:" << sat << endl;

             typeValueMap tvMap = f.body[sat];

             cout << tvMap << endl;

             map<std::string,std::vector<RinexObsID> > mapObsTypes(hdr.mapObsTypes);
             const vector<RinexObsID> types = mapObsTypes[sat.toString().substr(0,1)];

             std::vector<RinexDatum> dataVec;

             for(size_t i=0; i<types.size(); i++)
             {
                 cout << types[i].asString() << endl;;

                 TypeID type = ConvertToTypeID(types[i],sat);

                 cout << "gnss type:" << type << endl;

                 const int n = GetCarrierBand(types[i]);
                 cout << "n:" << n << endl;

                 cout << types[i].type << endl;

                 RinexDatum rinexDatum;

                 if(types[i].type == ObsID::otC)         // Range
                 {
                     if(tvMap.find(type) != tvMap.end())
                     {
                        rinexDatum.data = tvMap[ type ] ;
                     }
                     else
                     {
                        rinexDatum.data == 0.0;
                     }
                 }
                 else if(types[i].type == ObsID::otL)    // Phase
                 {
                     if(tvMap.find(type) != tvMap.end())
                     {
                         if(getWavelength(sat,n) != 0.0) 
                         {
                             rinexDatum.data = tvMap[type]/getWavelength(sat,n);

                             // n=1 2 5 6 7 8 9
                             if(n == 1)
                             {
                                 rinexDatum.lli =  tvMap[TypeID::LLI1] ;
                                 rinexDatum.ssi =  tvMap[TypeID::SSI1] ;
                             }
                             else if(n == 2)
                             {
                                 rinexDatum.lli  = tvMap[TypeID::LLI2] ;
                                 rinexDatum.ssi  = tvMap[TypeID::SSI2] ;
                             }
                             else if(n == 3)
                             {
                                 rinexDatum.lli  = tvMap[TypeID::LLI3] ;
                                 rinexDatum.ssi  = tvMap[TypeID::SSI3] ;
                             }
                             else if(n == 5)
                             {
                                 rinexDatum.lli  = tvMap[TypeID::LLI5] ;
                                 rinexDatum.ssi  = tvMap[TypeID::SSI5] ;
                             }
                             else if(n == 6)
                             {
                                 rinexDatum.lli  = tvMap[TypeID::LLI6] ;
                                 rinexDatum.ssi  = tvMap[TypeID::SSI6] ;
                             }
                             else if(n == 7)
                             {
                                 rinexDatum.lli  = tvMap[TypeID::LLI7] ;
                                 rinexDatum.ssi  = tvMap[TypeID::SSI7] ;
                             }
                             else if(n == 8)
                             {
                                 rinexDatum.lli  = tvMap[TypeID::LLI8] ;
                                 rinexDatum.ssi  = tvMap[TypeID::SSI8] ;
                             }
                             else if(n == 9)
                             {
                                 rinexDatum.lli  = tvMap[TypeID::LLI9] ;
                                 rinexDatum.ssi  = tvMap[TypeID::SSI9] ;
                             }
                         }
                         else
                         {
                            rinexDatum.data == 0.0;
                         }
                     }
                     else
                     {
                         rinexDatum.data == 0.0;
                     }
                 }
                 else
                 {
                     rinexDatum.data = tvMap[ type ] ;
                 }

                 cout << rinexDatum.asString() << endl;
                 dataVec.push_back(rinexDatum);

             }  // end of 'for(int i=0;i<types.size();i++)'

             rod.obs[sat] = dataVec;
         }

         s << rod;

         return s;

      }  // End of "try" block
      catch (...)
      {
         return s;
      }

   }   // End of stream input for gnssRinex



}  // End of namespace gpstk
